package com.map;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import net.sf.json.JSONObject;
import de.micromata.opengis.kml.v_2_2_0.Container;
import de.micromata.opengis.kml.v_2_2_0.Data;
import de.micromata.opengis.kml.v_2_2_0.Document;
import de.micromata.opengis.kml.v_2_2_0.ExtendedData;
import de.micromata.opengis.kml.v_2_2_0.Feature;
import de.micromata.opengis.kml.v_2_2_0.Folder;
import de.micromata.opengis.kml.v_2_2_0.Kml;
import de.micromata.opengis.kml.v_2_2_0.KmlFactory;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
import de.micromata.opengis.kml.v_2_2_0.Point;

public class PointOperatorFileImp implements PointOperator {
	String path = "";
	Kml kml = null;
	
	/**
	 * return 添加的元素的ID
	 */
	public String insert(String json) {
		JSONObject feature = JSONObject.fromObject(json);
		System.out.println(feature);
		return addAFeatureToKml(feature);
	}
	public static void main(String[] args) {
		try {
			PointOperator pointOperator = new PointOperatorFileImp("D:\\apache-tomcat-6.0.32-map1\\webapps\\map1\\aaa.kml");
			String json = "{id:'f7303c7c-ac99-4949-8e2e-82e547217a3e',geometry:{lat:24,lng:124},name:'测试Name4',maintype:'测试MainTYpe3',subtype:'测试subType3',vicinity:'测试address4'}";
			System.out.println(pointOperator.update(json));
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}
	public PointOperatorFileImp(String filepath) throws FileNotFoundException {
		this.path = filepath;
		kml = getKml();
	}
	
	public void setPath(String path) {
		this.path = path;
	}
	
	private String addAFeatureToKml(JSONObject jsonObject){
		JSONObject geometry = jsonObject.getJSONObject("geometry");
		double lat = geometry.getDouble("lat");
		double lng = geometry.getDouble("lng");
		String name = jsonObject.getString("name");
		String maintype = jsonObject.getString("maintype");
		String subtype = jsonObject.getString("subtype");
		String vicinity = jsonObject.getString("vicinity");
		String id = UUID.randomUUID().toString();
		boolean success = createMarker(lat, lng, maintype,subtype, name, vicinity,id);
		if(success){
			return id;
		}else{
			return "";
		}
	}
	
	public Kml getKml() {
		File file = new File(this.path);
		Kml iKml = null;
		if(file.exists()){
			try {
				iKml = Kml.unmarshalFromKmz(file)[0];
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			try {
				if(iKml==null){
					throw new Exception();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			if(iKml==null){
				try {
					throw new Exception("kml为null");
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			return iKml;
		}
		else{
			this.kml = iKml = KmlFactory.createKml();
			this.marshalKmlFile();
			if(iKml==null){
				try {
					throw new Exception("kml为null");
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			return iKml;
		}
	}
	
	private Document getDocument() {
		Document document = (Document)kml.getFeature();
		if(null==document){
			document = kml.createAndSetDocument();
			document.setId("rootDocument");
			marshalKmlFile(); 
		}
		return document;
	}
	
	private Folder getMainTypeFolder(String name, boolean isCreate) {
		Folder folder = null;
		Document document = this.getDocument();
		List<Feature> features = document.getFeature();
		for (int i = 0; i < features.size(); i++) {
			Feature feature = features.get(i);
			if(feature instanceof Folder && feature.getName().equalsIgnoreCase(name)){
				return (Folder)feature;
			}
		}
		if(isCreate){
			folder = document.createAndAddFolder();
			folder.setId(UUID.randomUUID().toString());
			folder.setName(name);
			marshalKmlFile();
		}
		return folder;
	}
	
	private Folder getSubTypeFolder(Folder parent,String name, boolean isCreate) {
		Folder folder = null;
		List<Feature> features = parent.getFeature();
		for (int i = 0; i < features.size(); i++) {
			Feature feature = features.get(i);
			if(feature instanceof Folder && feature.getName().equalsIgnoreCase(name)){
				return (Folder)feature;
			}
		}
		if(isCreate){
			folder = parent.createAndAddFolder();
			folder.setId(UUID.randomUUID().toString());
			folder.setName(name);
			marshalKmlFile();
		}
		return folder;
	}
	
	private boolean createMarker(double lat, double lng, String maintype, String subtype,String name, String address,String id) {
		Folder folder = getSubTypeFolder(getMainTypeFolder(maintype,true), subtype,true);
		Placemark placemark = folder.createAndAddPlacemark();
		placemark.setId(id);
		placemark.setName(name);
		placemark.setOpen(true);
		placemark.setDescription(address);
		ExtendedData value = new ExtendedData();
		List<Data> data = new ArrayList<Data>();
		data.add(new Data(maintype).withName("maintype"));
		data.add(new Data(subtype).withName("subtype"));
		value.setData(data);
		placemark.setExtendedData(value);
		placemark.createAndSetPoint().addToCoordinates(lng, lat);
		marshalKmlFile();
		return true;
	}
	
//	@Override
	public boolean remove(String id) {
		return removeMarker(getDocument(), id);
	}
	
	private boolean removeMarker(Container container, String id) {
		List<Feature> listFeature = null;
		if(container instanceof Document){
			listFeature = ((Document)container).getFeature();
			Document document = (Document)container;
			listFeature = document.getFeature();
			for (int i = 0; i < listFeature.size(); i++) {
				Feature feature = listFeature.get(i);
				if(feature instanceof Folder){
					if(removeMarker((Folder)feature, id)){
						return true;
					}
				}
				else if(feature instanceof Placemark){
					Placemark placemark = (Placemark)feature;
					if(id.equals(placemark.getId())){
						listFeature.remove(feature);
						marshalKmlFile();
						return true;
					}
				}
			}
		}
		else if(container instanceof Folder){
			Folder folder = (Folder)container;
			listFeature = folder.getFeature();
			for (int i = 0; i < listFeature.size(); i++) {
				Feature feature = listFeature.get(i);
				if(feature instanceof Folder){
					if(removeMarker((Folder)feature, id)){
						return true;
					}
				}
				else if(feature instanceof Placemark){
					Placemark placemark = (Placemark)feature;
					if(id.equals(placemark.getId())){
						listFeature.remove(feature);
						marshalKmlFile();
						return true;
					}
				}
			}
		}
		return false;
	}
	
//	@Override
	public boolean update(String json) {
		JSONObject object = JSONObject.fromObject(json);
		String id = object.getString("id");
		object.remove("id");
		return updateMarker(getDocument(), id, object);
	}
	
	private boolean updateMarker(Container container, String id, JSONObject jsonObject) {
		List<Feature> listFeature = null;
		if(container instanceof Document){
			listFeature = ((Document)container).getFeature();
			Document document = (Document)container;
			listFeature = document.getFeature();
			return updateFeatureMarker(listFeature,id,jsonObject);
		}
		else if(container instanceof Folder){
			Folder folder = (Folder)container;
			listFeature = folder.getFeature();
			return updateFeatureMarker(listFeature,id,jsonObject);
		}
		return false;
	}	
	
	private boolean updateFeatureMarker(List<Feature> listFeature,String id, JSONObject jsonObject) {
		for (int i = 0; i < listFeature.size(); i++) {
			Feature feature = listFeature.get(i);
			if(feature instanceof Folder){
				if(updateMarker((Folder)feature, id, jsonObject)){
					return true;
				}
			}
			else if(feature instanceof Placemark){
				boolean modifyed = false;
				Placemark placemark = (Placemark)feature;
				if(id.equals(placemark.getId())){
					JSONObject geometry = jsonObject.getJSONObject("geometry");
					if(null!=geometry){
						double lat = geometry.getDouble("lat");
						double lng = geometry.getDouble("lng");
						Point point = (Point)placemark.getGeometry();
						point.getCoordinates().clear();
						point.addToCoordinates(lng, lat);
						modifyed = true;
					}
					String name = jsonObject.getString("name");
					if(null!=name){
						placemark.setName(name);
					}
					String vicinity = jsonObject.getString("vicinity");
					if(vicinity!=null){
						placemark.setDescription(vicinity);
					}
					String maintype = jsonObject.getString("maintype");
					String subtype = jsonObject.getString("subtype");
					if(null!=maintype&&null!=subtype){
						listFeature.remove(feature);
						Folder folder = getSubTypeFolder(getMainTypeFolder(maintype, true),subtype,true);
						folder.getFeature().add(placemark);
					}
					marshalKmlFile();
					return true;
				}
			}
		}
		return false;
	}
	
//	@Override
	/**
	 * 	{type:'maintype',value:'酒店'} 
	 	or {type:'gettypes',value:'酒店'} 
		or {type:'subtype',value:['酒店','高级酒店']}
		or {type:'name', value:'假日酒店'} 
		or {type:'id', value:'787a9e4b-bf03-4dcd-bd36-003581fd942d'}
	 */
	public Kml query(String json) {
		Kml tempKml = KmlFactory.createKml();
		Document document = tempKml.createAndSetDocument();

		JSONObject object = JSONObject.fromObject(json);
		String type = object.getString("type");
		String value = object.getString("value");
		value = value.equalsIgnoreCase("null")?null:value;
		if("id".equalsIgnoreCase(type)){
			Feature feature = getFeatureById(value);
			if(null!=feature){
				document.getFeature().add(feature.clone());
			}
		}
		//获取所有的type信息，包括mainType和subType
		else if("gettypes".equalsIgnoreCase(type)){
			List<Feature> result = getTypesInfo(value);
			document.setFeature(result);
		}
		else if("match".equalsIgnoreCase(type)){
			List<Placemark> placemarks = getPlaceMarkersByKeyword(value);
			List<Feature> features = document.getFeature();
			for (int i = 0; i < placemarks.size(); i++) {
				features.add(placemarks.get(i).clone());
			}
		}
		return tempKml;
	}
	
	/**
	 * 获取类型（type）文件夹信息
	 * @param value：value如果为null，则返回整个document中所有的types所在的文件夹信息
	 * @return
	 */
	private List<Feature> getTypesInfo(String value){
		Document document2 = getDocument();
		List<Feature> list = document2.getFeature();
		List<Feature> result = new ArrayList<Feature>();
		for (int i = 0; i < list.size(); i++) {
			Feature mainTypeFeature = list.get(i);
			if(mainTypeFeature instanceof Folder){
				Folder mainTypeFolder = (Folder)mainTypeFeature;
				if(null==value||value.equalsIgnoreCase(mainTypeFolder.getName())){
					Folder tempMainType = mainTypeFolder.clone();
					List<Feature> tempSubTypes = tempMainType.getFeature();
					tempSubTypes.clear();
					List<Feature> list2 = mainTypeFolder.getFeature();
					for (int j = 0; j < list2.size(); j++) {
						Feature subTypeFeature = list2.get(j);
						if(subTypeFeature instanceof Folder){
							Folder folder = (Folder)subTypeFeature;
							Folder temp = folder.clone();
							temp.getFeature().clear();
							tempSubTypes.add(temp);
						}
					}
					result.add(tempMainType);
				}
			}
		}
		return result;
	}
	
	private Feature getFeatureById(String id) {
		return getFeatureById(this.getDocument(), id);
	}
	
	private Feature getFeatureById(Container container, String id) {
		if(container instanceof Document){
			Document document = (Document)container;
			List<Feature> features = document.getFeature();
			return getFeatureById(features,id);
		}
		else if(container instanceof Folder){
			Folder folder = (Folder)container;
			List<Feature> features = folder.getFeature();
			return getFeatureById(features,id);
		}
		return null;
	}
	
	private Feature getFeatureById(List<Feature> features, String id) {
		for (int i = 0; i < features.size(); i++) {
			Feature result = null;
			Feature feature = features.get(i);
			if(feature.getId().equalsIgnoreCase(id)){
				result =  feature;
			}
			else if(feature instanceof Container){
				Container container = (Container)feature;
				result = getFeatureById(container, id);
			}
			if(null!=result){
				return result;
			}
		}
		return null;
	}
	
	private List<Placemark> getPlaceMarkersByKeyword(String keyword){
		List<Placemark> result = new ArrayList<Placemark>();
		List<Placemark> placemarks = getAllPlaceMarker();
		for (int i = 0; i < placemarks.size(); i++) {
			Placemark placemark = placemarks.get(i);
			String description = placemark.getDescription();
			if(placemark.getName().contains(keyword)||description.contains(keyword)){
				result.add(placemark);
			}
		}
		return result;
	}
	
	private List<Folder> getMainTypeFolders() {
		List<Folder> result = new ArrayList<Folder>();
		Document document = getDocument();
		List<Feature> mainTypes = document.getFeature();
		for (int i = 0; i < mainTypes.size(); i++) {
			Feature mainType = mainTypes.get(i);
			if(mainType instanceof Folder){
				result.add((Folder)mainType);
			}
		}
		return result;
	}
	
	private List<Folder> getAllSubTypeFolders() {
		List<Folder> result = new ArrayList<Folder>();
		Document document = getDocument();
		List<Feature> mainTypes =  document.getFeature();
		for (int i = 0; i < mainTypes.size(); i++) {
			Feature mainType = mainTypes.get(i);
			if(mainType instanceof Folder){
				List<Feature> subTypes = ((Folder)mainType).getFeature();
				for (int j = 0; j < subTypes.size(); j++) {
					Feature subType = subTypes.get(j);
					if(subType instanceof Folder){
						result.add((Folder)subType);
					}
				}
			}
		}
		return result;
	}
	
	private List<Placemark> getAllPlaceMarker() {
		List<Placemark> result = new ArrayList<Placemark>();
		Document document = getDocument();
		List<Feature> mainTypes =  document.getFeature();
		for (int i = 0; i < mainTypes.size(); i++) {
			Feature mainType = mainTypes.get(i);
			if(mainType instanceof Folder){
				List<Feature> subTypes = ((Folder)mainType).getFeature();
				for (int j = 0; j < subTypes.size(); j++) {
					Feature subType = subTypes.get(j);
					if(subType instanceof Folder){
						List<Feature> placeMarkers = ((Folder)subType).getFeature();
						for (int k = 0; k < placeMarkers.size(); k++) {
							Feature placeMarker = placeMarkers.get(k);
							if(placeMarker instanceof Placemark){
								result.add((Placemark)placeMarker);
							}
						}
					}
				}
			}
		}
		return result;
	}
	
	private void marshalKmlFile() {
		try {
//			OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(this.path), "UTF-8");
			kml.marshalAsKmz(this.path);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
